<--- %%NOBANNER%% --> varobs.sas
 BackForward

/*-------------------<-- Start of Description-->---------------------\
| Retrieve the observation number for a variable in a dataset by     |
| giving a value;                                                    |
|---------------------<-- End of Description-->----------------------|
|--------------------------------------------------------------------|
|------------<-- Start of Files or Arguments Needed-->---------------|
| arguments:                                                         |
|    indata  - the name of a data set;                               |
|    varname - the 1st, 2nd or a valid variable name do you want;    |
|    value   - variable value you want to check;                     |
| Basically, it retrieve the observation number for the variable in  |
| the datset for the given value;                                    |
|-------------<-- End of Files or Arguments Needed-->----------------|
|--------------------------------------------------------------------|
|------------------<-- Start of Files Created-->---------------------|
| Example: %put %varobs(sashelp.library, 2, test);                   |
|          %put %varobs(sashelp.library, 2, 3);                    |
| Usage:   %varobs(indata, varname, value);                          |
\-------------------<-- End of Files Created-->---------------------*/
%macro varobs(indata, varname, value);
%let _varobsdsid_=%sysfunc(open(&indata,i));
%if (&_varobsdsid_) %then %do;
   %if (%chk_type(&varname)=1) %then %do;
      %if (&varname le %sysfunc(attrn(&_varobsdsid_,NVARS))) %then 
         %let varname=%sysfunc(varname(&_varobsdsid_,&varname));
      %else %do;
         %put ==> Alert! Dataset %data(&indata) does not have %trim(left(&varname)) variables!; .
         %goto finish;
      %end;
   %end;
   %else %do;
      %let _varobsvarnum_=%sysfunc(varnum(&_varobsdsid_,&varname));
      %if (&_varobsvarnum_ le 0) %then %do;
         %if (%quote(%upcase(%sysfunc(dequote(&varname)))) = %quote(NVARS)) %then
            %let varname=%sysfunc(varname(&_varobsdsid_,%sysfunc(attrn(&_varobsdsid_,NVARS))));
         %else %do;
            %put ==> Alert! Dataset %data(&indata) does not have variable %trim(%quote(%left(%quote(%upcase(&varname)))))! A valid variable name;
            %put +++        or a valid option (NVARS, for the last variable for the dataset) is required.; .
            %goto finish;
         %end;
      %end;
   %end;
   %let value=%trim(%quote(%left(%quote(%upcase(%sysfunc(dequote(&value)))))));
   %let _varobsobsi_=0; %syscall set(_varobsdsid_); %let &varname=;
   %do %while((%quote(&value) ne %quote(%upcase(&&&varname))) and (%sysfunc(fetchobs(&_varobsdsid_, %eval(&_varobsobsi_+1)))=0));
      %let _varobsobsi_=%eval(&_varobsobsi_+1);
   %end; 
   %if (&_varobsobsi_ lt %sysfunc(attrn(&_varobsdsid_,NOBS))) %then %do;
      &_varobsobsi_
      %put --> Note: The smallest observation of variable %trim(%quote(%left(%quote(%upcase(&varname))))) with the value of %trim(%quote(%left(%quote(&value))));
      %put +++       is %trim(%left(&_varobsobsi_)).;
   %end;
   %else %if (&_varobsobsi_ = %sysfunc(attrn(&_varobsdsid_,NOBS))) and (%quote(%upcase(&value)) = %quote(%upcase(&&&varname))) %then %do; 
      &_varobsobsi_
      %put --> Note: Only the last observation (%trim(%left(&_varobsobsi_))) of variable %trim(%quote(%left(%quote(%upcase(&varname))))) has the value of %trim(%quote(%left(%quote(&value)))).;
   %end;
   %else %do;
	   %put ==> Alert! Variable %trim(%quote(%left(%quote(%upcase(&varname))))) does not have a value of %quote(%upcase(&value)) in dataset %data(&indata)!; 0
	   %goto finish;
   %end;
   %let _varobsrc_=%sysfunc(close(&_varobsdsid_));
%end;
%else %do; .
   %put ==> Alert! Dataset %data(&indata) does not exist!; 
%end;
%finish:;
%mend varobs;